#include "ForwardLinkedListType.h"

#include "Containers/ReflectableForwardLinkedList.h"
#include "Reflection/GenericInfo.h"
#include "Reflection/PlaceholderType.h"
#include "Reflection/TypeInstance.h"
#include "GarbageCollectable.h"

CString CForwardLinkedListType::PlaceholderName = U"T";

CForwardLinkedListType::CForwardLinkedListType()
    : CType(
        STypeID(CType::GetEngineCoreNamespace()+U"::TNativeForwardLinkedList",true)
        ,ETypeFlags::Generic | ETypeFlags::ForwardLinkedList
        )
{
    GenericInfo= new CGenericInfo();

    auto PlaceholderType = new CPlaceholderType(
        STypeID(GetFullName()+U"::"+PlaceholderName,true)
        ,ETypeFlags::None
        ,0
        ,this);
    
    GenericInfo->PlaceholderTypes.Add(PlaceholderType);

}

CForwardLinkedListType *CForwardLinkedListType::GetStaticType()
{
    static CForwardLinkedListType *StaticType = new CForwardLinkedListType();
    return StaticType;
}

CString CForwardLinkedListType::CreateTypeName(const CString &ElementType)
{
    return STypeID::CreateTemplateTypeName(
        GetStaticType()->GetFullName()
        , {ElementType}
        , {PlaceholderName});
}

STypeID CForwardLinkedListType::CreateID(const SDecoratedType &ElementType)
{
    return STypeID(GetStaticType()->ID, {ElementType.BasicType->ID}, {PlaceholderName});
}

static uint8_t RegisterTypesCaller=(CForwardLinkedListType::GetStaticType(),0);

class CForwardLinkedListInstance : public ITypeInstance
{
protected:
    CForwardLinkedListGeneralized * Type;
public:
    CForwardLinkedListInstance(CForwardLinkedListGeneralized * InType)
        :Type(InType)
    {
    }

    virtual uint32_t GetSize() override
    {
        return sizeof(CReflectableForwardLinkedList);
    }

    virtual void InitInstance(void * Memory) override
    {
        new (Memory) CReflectableForwardLinkedList();
    }

    virtual void EraseInstance(void * Instance) override
    {
        ((CReflectableForwardLinkedList *)Instance)->Clear(Type->GetElementType().BasicType);
    }

    virtual void CloneInstance(const void * Instance, void * TargetMemory) override
    {
        new (TargetMemory) CReflectableForwardLinkedList(Type->GetElementType().BasicType, *(const CReflectableForwardLinkedList *)Instance);
    }

    virtual uint64_t GetInstanceHash(const void * Instance) const override
    {
        return ((CReflectableForwardLinkedList const*)Instance)->GetHashCode(Type->GetElementType().BasicType);
    }

    virtual bool IsInstanceEqual(const void * Instance0, const void * Instance1) const override
    {
        return ((CReflectableForwardLinkedList const*)Instance0)->IsEqual(Type->GetElementType().BasicType, *(const CReflectableForwardLinkedList *)Instance1);
    }

    virtual CString ToDebugString(const void * Instance) const override
    {
        return  Type->GetFullName();
    }

    virtual void * CreateInstance() override
    {
        return new CReflectableForwardLinkedList();
    }

    virtual void ResetAllocated(void * Memory) override
    {
        ((CReflectableForwardLinkedList *)Memory)->Clear(Type->GetElementType().BasicType);
    }

};

class CForwardLinkedListGC:public IGarbageCollectable
{
protected:
    CForwardLinkedListGeneralized * Type;
public:
    CForwardLinkedListGC(CForwardLinkedListGeneralized* InType)
        :Type(InType)
    {
    }

    //收集指定对象引用的对象,如果引用了多次，就会重复添加
    virtual void CollectReferencedObjects(
        void* InInstance,
        TForwardForwardLinkedList<RObject*>& OutReferencedObjects
    ) override
    {
        auto ElementType = Type->GetElementType().BasicType;

        auto ForwardLinkedList = (CReflectableForwardLinkedList *)InInstance;
        for(auto& Node:*ForwardLinkedList)
        {
            ElementType->GarbageCollectable
                ->CollectReferencedObjects(Node.GetData(),OutReferencedObjects);
        }
    }

};

CForwardLinkedListGeneralized::CForwardLinkedListGeneralized(const SDecoratedType& InElementType)
    : CType(
         CForwardLinkedListType::CreateID(InElementType)
        ,ETypeFlags::ForwardLinkedList | ETypeFlags::Generalized
         | (InElementType.BasicType->CanUseInScript() ? ETypeFlags::None : ETypeFlags::CantUseInScript)
        )
{
    Instancable = new CForwardLinkedListInstance(this);

    GeneralizedInfo = new CGeneralizedInfo();
    GeneralizedInfo->TemplateType = CForwardLinkedListType::GetStaticType();
    GeneralizedInfo->TypeArguments.Add(InElementType.BasicType);

    GeneralizedInfo->TemplateType->GenericInfo->GeneralizedTypes.Add(this);
    reinterpret_cast<CGenericInfo *>(GeneralizedInfo->TemplateType->GenericInfo)
        ->GenericMap.Add(TVector<CType*>({InElementType.BasicType}), this);

    //垃圾回收接口
    if(InElementType.BasicType->GarbageCollectable)
    {
        GarbageCollectable=new CForwardLinkedListGC(this);
    }

}

SDecoratedType CForwardLinkedListGeneralized::GetElementType() const
{
    return GeneralizedInfo->TypeArguments[0];
}

CForwardLinkedListGeneralized *CForwardLinkedListGeneralized::FindOrAddType(const SDecoratedType &InElementType)
{
    CGenericInfo *GenericInfo =CForwardLinkedListType::GetStaticType()->GenericInfo;

    if(GenericInfo->GenericMap.Contains({InElementType.BasicType}))
    {
        return (CForwardLinkedListGeneralized *)GenericInfo->GenericMap[{InElementType.BasicType}];
    }

    auto NewType = new CForwardLinkedListGeneralized(InElementType);
    GenericInfo->GenericMap.Add(TVector<CType*>({InElementType.BasicType}), NewType);
    return NewType;
}
